package com.franklin.ideaplugin.easytesting.rpc.dubbo;

import com.google.common.cache.*;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

/**
 * dubbo调用管理
 *
 * @author Ye Junhui
 * @since 2023/8/30
 */
public class DubboInvokerManager {

    private final Project project;

    //缓存接口这里是LoadingCache，LoadingCache在缓存项不存在时可以自动加载缓存
    private final Cache<DubboCacheKey, DubboInvoker> loadingInvokerCache
            //CacheBuilder的构造函数是私有的，只能通过其静态方法newBuilder()来获得CacheBuilder的实例
            = CacheBuilder.newBuilder()
            //设置并发级别为8，并发级别是指可以同时写缓存的线程数
            .concurrencyLevel(4)
            //设置写缓存后8秒钟过期
            .expireAfterWrite(20, TimeUnit.MINUTES)
            //设置缓存容器的初始容量为10
            .initialCapacity(10)
            //设置缓存最大容量为100，超过100之后就会按照LRU最近虽少使用算法来移除缓存项
            .removalListener(new RemovalListener<DubboCacheKey, DubboInvoker>() {
                @Override
                public void onRemoval(RemovalNotification<DubboCacheKey, DubboInvoker> removalNotification) {
                    DubboInvoker dubboInvoker = removalNotification.getValue();
                    dubboInvoker.close();
                }
            })
            .maximumSize(100)
            .build();

    public DubboInvokerManager(Project project) {
        this.project = project;
    }

    public static DubboInvokerManager getInstance(Project project) {
        return ServiceManager.getService(project, DubboInvokerManager.class);
    }

    public synchronized DubboInvoker getInvoker(
            String classQualifiedName,
            DubboConfig dubboConfig,
            Supplier<DubboInvoker> invokerSupplier
    ) {

        DubboCacheKey dubboCacheKey = new DubboCacheKey(classQualifiedName, dubboConfig);
        DubboInvoker dubboInvoker = loadingInvokerCache.getIfPresent(dubboCacheKey);
        //缓存为空
        if (Objects.isNull(dubboInvoker)) {
            dubboInvoker = invokerSupplier.get();
            loadingInvokerCache.put(dubboCacheKey, dubboInvoker);
        }else {
            //配置变更
            if (!dubboConfig.equals(dubboInvoker.getDubboConfig())){
                dubboInvoker.close();
                dubboInvoker = invokerSupplier.get();
                loadingInvokerCache.put(dubboCacheKey, dubboInvoker);
            }else {
                //初始化失败
                if (!dubboInvoker.isInit()){
                    dubboInvoker.close();
                    dubboInvoker = invokerSupplier.get();
                    loadingInvokerCache.put(dubboCacheKey, dubboInvoker);
                }
            }
        }
        return dubboInvoker;
    }

    /**
     * dubbo缓存key
     */
    @Data
    @EqualsAndHashCode
    @AllArgsConstructor
    private static class DubboCacheKey{
        private String classQualifiedName;
        private DubboConfig dubboConfig;
    }
}
